package pnu.ssm.view;

import java.util.Scanner;

import pnu.ssm.controller.manager.JobManager;
import pnu.ssm.controller.manager.TransporterManager;
import pnu.ssm.ga.FitnessCalc;
import pnu.ssm.ga.GeneticAlgorithm;
import pnu.ssm.ga.Population;
import pnu.ssm.http.Request;
import flexjson.JSONDeserializer;

public class Main {
	
	private static final int maxGeneration = 50000;
	private static final int stopGap = 100;
	
	
	public static void main(String[] args) {
		startConsoleMode();
	}
	
	public static void startConsoleMode(){
		Scanner scan = new Scanner(System.in);
		Dispatcher.Debug = false;
		Dispatcher dispatcher = new Dispatcher();
		dispatcher.readFile();
		
		while(true){
			System.out.print("GENETIC ALGORITHM (G/g) or Optimum Solution (O/o) or Quit(Q/q) : ");
			String answer = scan.nextLine();
			
//			System.out.print("DEBUG MODE? (true or false) : ");
//			Dispatcher.Debug = scan.nextBoolean();
//			scan.nextLine();
			
			if(answer.equalsIgnoreCase("g")){
				System.out.print("Do you want to set Option of GENETIC ALGORITHM? (Yy/Nn) : ");
				answer = scan.nextLine();
				if(answer.equalsIgnoreCase("y")){
					System.out.print("UniformRate (default is 0.5) : ");
					double uniformRate = scan.nextDouble();
					System.out.print("MutationRate (default is 0.015) : ");
					double mutationRate = scan.nextDouble();
					System.out.print("Elitism (default is true) : ");
					boolean elitism = scan.nextBoolean();
					System.out.print("TournamentSize (default is 5) : ");
					int tournamentSize = scan.nextInt();
					optionGeneticAlgorithm(uniformRate, mutationRate, elitism, tournamentSize);
				}

				System.out.println("");
				dispatcher.init();
				geneticAlorithm(dispatcher, scan);
				answer = scan.nextLine();
			} else if (answer.equalsIgnoreCase("o")) {
				dispatcher.init();
				optimumAlgorithm(dispatcher, scan);
			} else if (answer.equalsIgnoreCase("q")){
				break;
			} else {
				System.out.println("Enter a correct answer.");
			}
		}
		
		System.out.println("Exit.");
	}
	
	public static void geneticAlorithm(Dispatcher dispatcher, Scanner scan){
		long before = System.currentTimeMillis();
		Population myPop = new Population(50, true);
		int generationCount = 0;
		
		for(int i=0; i<maxGeneration; i++){
			generationCount++;
			int currFittest = myPop.getFittestIndividual().getFitness();
			System.out.println(myPop.getFittestIndividual());
			System.out.println("Generation: " + generationCount + " Fittest: " + currFittest);
			myPop = GeneticAlgorithm.evolvePopulation(myPop);
			if(Dispatcher.Debug || (generationCount % stopGap == 0)){
				String continueFlag = scan.nextLine();
				if(continueFlag.equalsIgnoreCase("q"))
					break;
			}
			dispatcher.init();
		}
		
		long after = System.currentTimeMillis();
		long diff = (after - before)/1000;
		System.out.println("소요 시간 : "+diff + "초");
		System.out.println(myPop.getFittestIndividual());
	}
	
	public static void optimumAlgorithm(Dispatcher dispatcher, Scanner scan){
		dispatcher.init();
		long before = System.currentTimeMillis();
		int fittest = Integer.MAX_VALUE;
		int num_transporter = TransporterManager.getInstance().getSize();
		int num_job = JobManager.getInstance().getSize();
		int iter = (int)Math.pow(num_transporter, num_job);
		int arr[] = new int[num_job];
		int optimumArr[] = new int[num_job];
		for(int i=0; i<arr.length; i++) arr[i] = 0;
		
		for(int j=0; j<iter; j++){
			baseConvert(num_job-1, arr, num_transporter);
			int tFittest = FitnessCalc.getFitnessByArr(arr);
			if (tFittest < fittest) {
				fittest = tFittest;
				for(int i=0; i<arr.length; i++){
					optimumArr[i] = arr[i];
				}
			}
			printArr(arr);
			System.out.println(" fittest : "+fittest);
			arr[num_job-1] += 1;
			dispatcher.init();
			if(Dispatcher.Debug){
				String continueFlag = scan.nextLine();
				if(continueFlag.equalsIgnoreCase("q"))
					break;
			}
		}
		
		long after = System.currentTimeMillis();
		long diff = (after - before)/1000;
		System.out.print("Optimum Solution : ");
		printArr(optimumArr);
		System.out.println();
		System.out.println("소요 시간 : "+diff + "초");
		System.out.println("optimum fittest : "+fittest);
	}
	
	public static void optionGeneticAlgorithm(double uniformRate, double mutationRate, boolean elitism, int tournamentSize){
		GeneticAlgorithm.uniformRate = uniformRate;
		GeneticAlgorithm.mutationRate = mutationRate;
		GeneticAlgorithm.elitism = elitism;
		GeneticAlgorithm.tournamentSize = tournamentSize;
	}

	public static void printArr(int arr[]){
		for(int k=0; k<arr.length; k++)
			System.out.print(arr[k]);
	}
	
	public static void baseConvert(int level, int arr[], int base){
		if(level < 0) {
			return;
		}
		if(arr[level] == base && level-1 >= 0){
			arr[level] = 0;
			arr[level-1] += 1;
			baseConvert(level-1, arr, base);
		}
	}
}

